﻿using System;
using System.Text;

namespace CodedUITestExtensions.Tree
{
    /// <summary>
    /// Tree.
    /// </summary>
    public class SimpleTree : IEquatable<SimpleTree>
    {
        private const string _levelSymbols = "--";

        /// <summary> Gets/sets tree children. </summary>
        public TreeNodeList Children { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:CodedUITestExtensions.Tree.SimpleTree"/> class.
        /// </summary>
        public SimpleTree()
        {
            Children = new TreeNodeList(null);
        }

        /// <summary>
        ///  Initializes a new instance of the <see cref="T:CodedUITestExtensions.Tree.SimpleTree"/> class.
        /// </summary>
        /// <param name="otherTree">Tree to copy from.</param>
        public SimpleTree(SimpleTree otherTree)
        {
            Children = new TreeNodeList(null);
            foreach (TreeNode otherNode in otherTree.Children)
            {
                TreeNode node = Children.Add(otherNode.Value);
                TraverseNodeToCopy(node, otherNode);
            }
        }

        /// <summary>
        /// Traverse tree node to copy structure from one node to another. 
        /// </summary>
        /// <param name="node">Tree node to copy from.</param>
        /// <param name="otherNode">Tree node to copy.</param>
        private static void TraverseNodeToCopy(TreeNode node, TreeNode otherNode)
        {
            foreach (TreeNode treeNode in otherNode.Children)
            {
                TreeNode childrenNode = node.Children.Add(treeNode.Value);
                TraverseNodeToCopy(childrenNode, treeNode);
            }
        }

        /// <summary>
        /// Equals.
        /// </summary>
        /// <param name="other">Tree.</param>
        /// <returns>Result.</returns>
        public bool Equals(SimpleTree other)
        {
            if (other == null)
            {
                return false;
            }

            int count = Children.Count;
            if (count != other.Children.Count)
            {
                return false;
            }

            for (int i = 0; i < count; ++i)
            {
                if (!Children[i].Equals(other.Children[i]))
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Equals.
        /// </summary>
        /// <param name="obj">Tree.</param>
        /// <returns>Result.</returns>
        public override bool Equals(Object obj)
        {
            return Equals(obj as SimpleTree);
        }

        /// <summary>
        /// GetHashCode.
        /// </summary>
        /// <returns>Result.</returns>
        public override int GetHashCode()
        {
            return Children.GetHashCode() ^ Children.Count.GetHashCode();
        }

        /// <summary>
        /// Gets string representation of tree.
        /// </summary>
        /// <returns>String representation of tree.</returns>
        public override string ToString()
        {
            var builder = new StringBuilder();
            builder.AppendLine();
            foreach (TreeNode node in Children)
            {
                builder.AppendLine(_levelSymbols + node.Value);
                TraverseNodeToGetString(node, builder, _levelSymbols);
            }

            return builder.ToString();

        }

        /// <summary>
        /// Traverse tree node to get its string representation.
        /// </summary>
        /// <param name="node">Tree node.</param>
        /// <param name="builder">StringBuilder with current string representation.</param>
        /// <param name="levelSymbols">Symbols to indicate levels.</param>
        private static void TraverseNodeToGetString(TreeNode node, StringBuilder builder, string levelSymbols)
        {
            levelSymbols = levelSymbols + _levelSymbols;
            TreeNodeList children = node.Children;
            if (children.Count > 0)
            {
                foreach (TreeNode treeNode in children)
                {
                    builder.AppendLine(levelSymbols + treeNode.Value);
                    TraverseNodeToGetString(treeNode, builder, levelSymbols);
                }
            }
        }
    }
}
